Skip to content

Layout Exercises

Toggle, Revisited

Earlier, we saw how to build a <Toggle /> component using Framer Motion:

We solved it in that example using the animate property, but now that we know about layout animations, there might be a better way!

Your mission is to update the code below so that it uses layout animations.

Acceptance Criteria:

  • The Toggle component should not use the animate property. Instead, the ball's position should be controlled with CSS, and it should be animated using a layout animation.

Code Playground

import React from 'react';
import { motion } from 'framer-motion';

import styles from './Toggle.module.css';

function Toggle({ value, onChange, ...delegated }) {
return (
<button
type="button"
role="switch"
aria-checked={value}
className={styles.wrapper}
onClick={() => onChange(!value)}
{...delegated}
>
<motion.span
className={styles.ball}
initial={false}
transition={{
type: 'spring',
stiffness: 500,
damping: 40,
}}
animate={{
x: value ? '100%' : '0%',
}}
/>
</button>
);
}

export default Toggle;

Solution:

Flex Demo

Let's recreate the “FlexDemo” component from my blog post, An Interactive Guide to Flexbox!

Most of the code has already been provided. Your mission is to apply the Flexbox settings according to the state variables, and to animate it using Framer Motion.

Acceptance Criteria:

  • The flexDirection, justifyContent, and alignItems state variables should be applied as an inline style to the demoArea element.
  • Framer Motion layout animations should be used to animate changing the various parameters.
  • The text should not be distorted when switching between parameters (for example, alignItems should be able to switch between stretch and center without any text warping).

Code Playground

import React from 'react';
import { motion } from 'framer-motion';

import styles from './FlexDemo.module.css';

function FlexDemo() {
const [flexDirection, setFlexDirection] = React.useState('row');
const [justifyContent, setJustifyContent] =
React.useState('flex-start');
const [alignItems, setAlignItems] = React.useState('stretch');

return (
<section className={styles.wrapper}>
<div className={styles.demoArea}>
{ITEMS.map((item) => (
<div key={item.id} className={styles.flexItem}>
{item.label}
</div>
))}
</div>

<div className={styles.controls}>
<SelectControl
label="flex-direction"
value={flexDirection}
onChange={(event) => setFlexDirection(event.target.value)}
>
<option value="row">row</option>
<option value="column">column</option>
</SelectControl>
<SelectControl
label="justify-content"
value={justifyContent}
onChange={(event) =>
setJustifyContent(event.target.value)
}
>
<option value="flex-start">flex-start</option>
<option value="flex-end">flex-end</option>
<option value="center">center</option>
<option value="space-between">space-between</option>
<option value="space-around">space-around</option>
<option value="space-evenly">space-evenly</option>
</SelectControl>
<SelectControl
label="align-items"
value={alignItems}
onChange={(event) => setAlignItems(event.target.value)}
>
<option value="stretch">stretch</option>
<option value="flex-start">flex-start</option>

Solution: